/*
 * Target: 2G5 DDR3 1A
 */
#include <stdio.h>
#include <termio.h>
#include <string.h>
#include <setjmp.h>
#include <sys/endian.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#ifdef _KERNEL
#undef _KERNEL
#include <sys/ioctl.h>
#define _KERNEL
#else
#include <sys/ioctl.h>
#endif

#include <machine/cpu.h>

#include <pmon.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <flash.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/net/if.h>
#include "mod_vgacon.h"
#include "mod_display.h"
void route_init();

#include <pflash.h>

#define CONFIG_PAGE_SIZE_64KB
#include "mipsregs.h"
#include "gzip.h"
#if NGZIP > 0
#include <gzipfs.h>
#endif /* NGZIP */

#ifdef LOONGSON_3A2H
#include <dev/pci/ahcisata.h>
extern struct cfdriver ahci_sd_cd;
#endif

//#define DEFAULT_LOOP_VARIABLE	10000
#define DEFAULT_LOOP_VARIABLE	60000   //mtf modify for 2k
//#define DEFAULT_DELAY_VARIABLE	10
#define DEFAULT_DELAY_VARIABLE	10000


#define LS1A_GMAC0_BASE		0xb2e10000
#define LS2K_GMAC0_BASE		0xbfe20000
#define LS2G_GMAC0_BASE		0x90000c0000000000
#define LS2G_GMAC1_BASE		0x90000d0000000000
#define MAC_OFFSET		0x0000
#define DMA_OFFSET		0x1000


static unsigned int mycount = 1;

int cmd_mycfg __P((int, char *[]));

static void synopGMACWriteReg(unsigned int RegBase, unsigned int RegOffset, unsigned int RegData )
{

	unsigned int addr;

	addr = RegBase + RegOffset;
#if 1//defined(LOONGSON_2G1A)
	if (RegBase == LS2K_GMAC0_BASE + MAC_OFFSET || RegBase == LS2K_GMAC0_BASE + DMA_OFFSET)
		*(volatile unsigned int *)addr = RegData;
	else
#endif
#if 0
		__asm __volatile(
			".set\tnoreorder\n\t"
			".set\tmips3\n\t"
			"lw $9,%0\n\t"
			"ld $8,%1\n\t"
			"sw $9,0x0($8)\n\t"
			:
			:"m"(RegData),"m"(addr)
			:"memory","$8","$9"
			);
#endif
	return;
}

static unsigned int  synopGMACReadReg(unsigned int RegBase, unsigned int RegOffset)
{

	unsigned int addr;
	unsigned int data;

	addr = RegBase + RegOffset;
#if 1//defined(LOONGSON_2G1A)
	if (RegBase == LS2K_GMAC0_BASE + MAC_OFFSET || RegBase == LS2K_GMAC0_BASE + DMA_OFFSET)
		data = *(volatile unsigned int *)addr;
#endif

#if 0
		__asm __volatile(
			".set\tnoreorder\n\t"
			".set\tmips3\n\t"
			"ld $8,%1\n\t"
			"lw $9,0x0($8)\n\t"
			"nop\n\t"
			"nop\n\t"
			"sw $9,%0\n\t"
			:"=m"(data)
			:"m"(addr)
			:"memory","$8","$9"
			);
#endif
	return data;
}

static void plat_delay(unsigned int delay)
{
	while (delay--);
	return;
}

static int synopGMAC_write_phy_reg(unsigned long long RegBase, unsigned int PhyBase, unsigned int RegOffset, unsigned short data)
{
	unsigned int addr;
	unsigned int loop_variable;

	synopGMACWriteReg(RegBase, 0x0014, data); // write the data in to GmacGmiiData register of synopGMAC ip

	addr = ((PhyBase << 11) & 0x0000f800) | ((RegOffset << 6) & 0x000007c0) | 0x00000002 | 0x0000000c;	//sw: add GmiiCsrclk

	addr = addr | 0x00000001; //set Gmii clk to 20-35 Mhz and Gmii busy bit

	synopGMACWriteReg(RegBase, 0x0010, addr);
	for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){
		if (!(synopGMACReadReg(RegBase, 0x0010) & 0x00000001)){
			break;
		}
		plat_delay(DEFAULT_DELAY_VARIABLE);
	}

	if(loop_variable < DEFAULT_LOOP_VARIABLE){
		return 0;
	} else {
		printf("Error::: PHY not responding Busy bit didnot get cleared !!!!!!\n");
		return -0;
	}
#if SYNOP_REG_DEBUG
	printf("write phy reg: offset = 0x%x\tdata = 0x%x",RegOffset,data);
#endif
}

static int dump(int argc,char **argv)	//gmacbase, regoffset
{
	unsigned int gmacbase;
	unsigned int phybase;
	unsigned int phyreg;
	unsigned int addr;
	unsigned int loop_variable;
	unsigned short data;
    unsigned short tmp = 0;

	if (3 != argc) {
		printf("m4-phy [phy reg number] [phy data]\n");
		return 0;
	}

		gmacbase = LS2K_GMAC0_BASE;
		phybase = 0;    //2k use 8211e chip, phybase use the number which is the first used by software cfg

	phyreg = (argv[1][0] - 48) * 10 + (argv[1][1] - 48);//48 is char 0 ascii

    if (48 <= argv[2][0] && argv[2][0] <= 57)   //0~9
        tmp = (argv[2][0] - 48) * 16 * 16 * 16;
    else if (97 <= argv[2][0] && argv[2][0] <= 102)
        tmp = (argv[2][0] - 97 + 10) * 16 * 16 * 16;

    if (48 <= argv[2][1] && argv[2][1] <= 57)   //0~9
        tmp += (argv[2][1] - 48) * 16 * 16;
    else if (97 <= argv[2][1] && argv[2][1] <= 102)
        tmp += (argv[2][1] - 97 + 10) * 16 * 16;

    if (48 <= argv[2][2] && argv[2][2] <= 57)   //0~9
        tmp += (argv[2][2] - 48) * 16;
    else if (97 <= argv[2][2] && argv[2][2] <= 102)
        tmp += (argv[2][2] - 97 + 10) * 16;

    if (48 <= argv[2][3] && argv[2][3] <= 57)   //0~9
        tmp += (argv[2][3] - 48);
    else if (97 <= argv[2][3] && argv[2][3] <= 102)
        tmp += (argv[2][3] - 97 + 10);

    data = tmp;
		
	printf("+++====----------------- phybase is : %d, phyreg is : %d, data is : 0x%x\n", phybase, phyreg, data);

#if 1
	synopGMACWriteReg(gmacbase, 0x0014, data);

	addr = ((phybase << 11) & 0x0000f800) | ((phyreg << 6) & 0x000007c0) | 0x0000000c | 2;//2 is write option
	addr = addr | 0x00000001 ; //Gmii busy bit

	synopGMACWriteReg(gmacbase, 0x0010, addr);

	for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){
		if (!(synopGMACReadReg(gmacbase, 0x0010) & 0x00000001)){
			 break;
		}
		plat_delay(DEFAULT_DELAY_VARIABLE);
	}
	if(loop_variable < DEFAULT_LOOP_VARIABLE)
		printf("write no err ~~~\n");//
	else{
		printf("Error::: PHY not responding Busy bit didnot get cleared !!!!!!\n");
		return -2;
	}
	printf("~~~~~~~ data written is 0x%x\n", data);
	return 0;
#endif
}

#include <sys/net/route.h>

static const Cmd Cmds[] =
{
	{"MyCmds"},
	{"m4-phy",	"[addr] [count]", 0, "dump address world", dump, 0, 99, CMD_REPEAT},
	{0, 0}
};


static void init_cmd __P((void)) __attribute__ ((constructor));

static void
init_cmd()
{
	cmdlist_expand(Cmds, 1);
}


